package com.mingzhi.order.service.impl;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.mingzhi.order.bean.Order;
import com.mingzhi.order.fegin.ProductFeginClient;
import com.mingzhi.order.service.OrderService;
import com.mingzhi.product.bean.Product;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private ProductFeginClient productFeginClient;


    @SentinelResource(value = "createOrder", blockHandler = "createOrderBlockHandler")
    @Override
    public Order createOrder(Long userId, Long productId) {
        //先获取商品信息

//        Product product = getProductByIdWithLoadBalancerAnnotation(productId);

        //使用feign 远程调用
        Product product = productFeginClient.getProductById(productId);
        Order order = new Order();
        order.setId(1L);
        //总金额是需要计算的
        //商品的价格
        BigDecimal price = product.getPrice();
        //数量*价格 =  总价
        BigDecimal multiply = price.multiply(new BigDecimal(product.getNum()));
        order.setTotalPrice(multiply);
        order.setUserId(userId);
        order.setNickName("明志");
        order.setAddress("杭州");
        // 商品列表  需要从商品服务中获取
        order.setProductList(Arrays.asList(product));
        return order;
    }

    /**
     * 创建订单的限流处理方法 针对 @SentinelResource注解 的限流处理方法
     * 兜底回调方法
     * 也可以使用 fallback = "createOrderBlockHandler" 这个主要处理业务逻辑的异常
     *
     * @param userId
     * @param productId
     * @return
     */
    public Order createOrderBlockHandler(Long userId, Long productId, BlockException e) {
        Order order = new Order();
        order.setId(1L);
        order.setUserId(userId);
        order.setNickName("明志");
        order.setAddress("杭州");
        order.setProductList(null);
        return order;
    }


    //获取单个商品信息
    private Product getProductById(Long productId) {
        //进行远程调用
        //1.获取到商品服务所在的所有机器ip + prot  需要用到springcloud提供的组件 discoveryClient
        List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
        ServiceInstance serviceInstance = instances.get(0);
        //http://127.0.0.1:9000/product/4
        String host = serviceInstance.getHost();
        int port = serviceInstance.getPort();
        String url = "http://" + host + ":" + port + "/product/" + productId;
        log.info("远程请求路径url:{}", url);
        //2.给远程发送请求即可
        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }

    //获取单个商品信息 有负载均衡功能 版本一
    private Product getProductByIdWithLoadBalancer(Long productId) {
        //进行远程调用
        //1.获取到商品服务所在的所有机器ip + prot
        ServiceInstance choose = loadBalancerClient.choose("service-product");
        //http://127.0.0.1:9000/product/4
        String host = choose.getHost();
        int port = choose.getPort();
        String url = "http://" + host + ":" + port + "/product/" + productId;
        log.info("远程请求路径url:{}", url);
        //2.给远程发送请求即可
        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }

    //获取单个商品信息 有负载均衡功能 版本二：基于注解的负载均衡
    private Product getProductByIdWithLoadBalancerAnnotation(Long productId) {
        //进行远程调用
        //http://127.0.0.1:9000/product/4
        String url = "http://service-product/product/" + productId;
        //给远程发送请求即可  service-product 会被动态替换
        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }
}
